package com.tbl.common.config;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.tbl.common.utils.DateUtils;
import com.tbl.common.utils.JsontoMap;
import com.tbl.modules.platform.controller.AbstractController;
import com.tbl.modules.wms.constant.EbsInterfaceEnum;
import com.tbl.modules.wms.entity.interfacelog.InterfaceDo;
import com.tbl.modules.wms.entity.interfacelog.InterfaceLog;
import com.tbl.modules.wms.entity.inventory.Inventory;
import com.tbl.modules.wms.service.baseinfo.FactoryAreaService;
import com.tbl.modules.wms.service.businessutils.BusinessUtilsService;
import com.tbl.modules.wms.service.interfacelog.InterfaceDoService;
import com.tbl.modules.wms.service.interfacelog.InterfaceLogService;
import com.tbl.modules.wms.service.inventory.InventoryRegistrationService;
import com.tbl.modules.wms.service.inventory.InventoryService;
import com.tbl.modules.wms.service.webservice.client.WmsService;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 定时任务
 * @author 70486
 */
@EnableAsync
@Component
@Configuration
public class Jobs extends AbstractController {

    /**
     * 2分钟
     */
    public final static long TWO_MINUTE =  60 * 1000 * 2;
    /**
     * 20分钟
     */
    public final static long TWENTY_MINUTE =  60 * 1000 * 20;
    /**
     * 1小时
     */
    public final static long ONE_HOUR =  60 * 1000 * 60;
    /**
     * 盘点登记服务
     */
    @Autowired
    private InventoryRegistrationService inventoryRegistrationService;
    /**
     * wms接口调用入口
     */
    @Autowired
    private WmsService wmsService;
    /**
     * 厂区信息
     */
    @Autowired
    private FactoryAreaService factoryAreaService;
    /**
     * 接口执行
     */
    @Autowired
    private InterfaceDoService interfaceDoService;
    /**
     * 接口日志
     */
    @Autowired
    private InterfaceLogService interfaceLogService;
    /**
     * 盘点计划
     */
    @Autowired
    private InventoryService inventoryService;
    /**
     * 线程池配置
     */
    @Resource
    private ThreadConfig threadConfig;
    /**
     * 业务流程公用服务
     */
    @Autowired
    private BusinessUtilsService businessUtilsService;

    /**
     * 离线接口多线程执行，2分钟一次
     */
    @Async
    @Scheduled(fixedDelay = TWO_MINUTE)
    public void fixedDelayJob(){
        List<InterfaceDo> lstInterfaceDo = interfaceDoService.findJobsInterfaceDos();
        if (lstInterfaceDo!=null && lstInterfaceDo.size()>0) {
            CountDownLatch countDownLatch = new CountDownLatch(lstInterfaceDo.size());
            for (InterfaceDo interfaceDo : lstInterfaceDo) {
                threadConfig.asyncServiceExecutor().execute(() -> {
                    try {
                        logger.info("线程--> " + Thread.currentThread().getName() + " 开始");
                        // 写业务
                        String returnInfo = "";
                        Map<String,Object> xmlMap = JsontoMap.parseJSON2Map(JSONObject.fromObject(interfaceDo.getParamsinfo()));
                        switch (interfaceDo.getInterfacecode()) {
                            case EbsInterfaceEnum.FEWMS008:
                                try {
                                    while (ConRunningMap.containsItem(EbsInterfaceEnum.FEWMS008 + interfaceDo.getQacode())){
                                        TimeUnit.MILLISECONDS.sleep(5000);
                                    }
                                    //把接口编码+质保号放到内存中
                                    ConRunningMap.addItem(EbsInterfaceEnum.FEWMS008 + interfaceDo.getQacode());
                                    returnInfo = wmsService.FEWMS008(xmlMap, interfaceDo.getQacode(), interfaceDo.getBatchNo());
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                                ConRunningMap.removeItem(EbsInterfaceEnum.FEWMS008 + interfaceDo.getQacode());
                                break;
                            case EbsInterfaceEnum.FEWMS030:
                                try {
                                    while (ConRunningMap.containsItem(EbsInterfaceEnum.FEWMS030 + interfaceDo.getQacode())){
                                        TimeUnit.MILLISECONDS.sleep(5000);
                                    }
                                    //把接口编码+质保号放到内存中
                                    ConRunningMap.addItem(EbsInterfaceEnum.FEWMS030 + interfaceDo.getQacode());
                                    returnInfo = wmsService.FEWMS030(xmlMap, interfaceDo.getQacode(), interfaceDo.getBatchNo());
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                                ConRunningMap.removeItem(EbsInterfaceEnum.FEWMS030 + interfaceDo.getQacode());
                                break;
                            case EbsInterfaceEnum.FEWMS025:
                                try {
                                    while (ConRunningMap.containsItem(EbsInterfaceEnum.FEWMS025 + interfaceDo.getQacode())){
                                        TimeUnit.MILLISECONDS.sleep(5000);
                                    }
                                    //把接口编码+质保号放到内存中
                                    ConRunningMap.addItem(EbsInterfaceEnum.FEWMS025 + interfaceDo.getQacode());
                                    returnInfo = wmsService.FEWMS025(xmlMap, interfaceDo.getQacode(), interfaceDo.getBatchNo());
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                                ConRunningMap.removeItem(EbsInterfaceEnum.FEWMS025 + interfaceDo.getQacode());
                                break;
                            case EbsInterfaceEnum.FEWMS024:
                                try {
                                    while (ConRunningMap.containsItem(EbsInterfaceEnum.FEWMS024 + interfaceDo.getQacode())){
                                        TimeUnit.MILLISECONDS.sleep(5000);
                                    }
                                    //把接口编码+质保号放到内存中
                                    ConRunningMap.addItem(EbsInterfaceEnum.FEWMS024 + interfaceDo.getQacode());
                                    returnInfo = wmsService.FEWMS024(xmlMap, interfaceDo.getQacode(), interfaceDo.getBatchNo());
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                                ConRunningMap.removeItem(EbsInterfaceEnum.FEWMS024 + interfaceDo.getQacode());
                                break;
                            case EbsInterfaceEnum.FEMES001:
                                try {
                                    while (ConRunningMap.containsItem(EbsInterfaceEnum.FEMES001 + interfaceDo.getQacode())){
                                        TimeUnit.MILLISECONDS.sleep(5000);
                                    }
                                    //把接口编码+质保号放到内存中
                                    ConRunningMap.addItem(EbsInterfaceEnum.FEMES001 + interfaceDo.getQacode());
                                    returnInfo = wmsService.FEMES001(xmlMap, interfaceDo.getQacode(), interfaceDo.getBatchNo());
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                                ConRunningMap.removeItem(EbsInterfaceEnum.FEMES001 + interfaceDo.getQacode());
                                break;
                            case EbsInterfaceEnum.FEWMS002:
                                try {
                                    while (ConRunningMap.containsItem(EbsInterfaceEnum.FEWMS002 + interfaceDo.getQacode())){
                                        TimeUnit.MILLISECONDS.sleep(5000);
                                    }
                                    //把接口编码+质保号放到内存中
                                    ConRunningMap.addItem(EbsInterfaceEnum.FEWMS002 + interfaceDo.getQacode());
                                    returnInfo = (String) wmsService.FEWMS002(xmlMap, interfaceDo.getQacode(),
                                            interfaceDo.getBatchNo()).get("returnData");
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                                ConRunningMap.removeItem(EbsInterfaceEnum.FEWMS002 + interfaceDo.getQacode());
                                break;
                            default:
                                break;
                        }

                        interfaceDo.setReturncode(returnInfo);
                        //返回报文去空，用于判断是否执行成功
                        String returnInfoTrim = returnInfo.replace(" ", "");
                        interfaceDo.setIssuccess(!returnInfoTrim.contains("<code>0</code>") && !returnInfoTrim.contains("\"code\":0")
                                && !returnInfoTrim.contains("S000A000") ? "2" : "1");
                        interfaceDo.setOperatetime(DateUtils.getTime());
                        interfaceDo.setExecutenum(interfaceDo.getExecutenum() + 1);
                        if (interfaceDo.getExecutenum() == 1 && "2".equals(interfaceDo.getIssuccess())){
                            interfaceDo.setFlasecontent(returnInfo);
                        }
                        interfaceDoService.updateById(interfaceDo);
                        logger.info("线程--> " + Thread.currentThread().getName() + " 结束");
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        // 这个不管是否异常都需要数量减,否则会被堵塞无法结束
                        countDownLatch.countDown();
                    }
                });
            }
            try {
                countDownLatch.await();
                logger.info("所有线程结束");
            } catch (Exception e) {
                logger.error("阻塞异常");
            }
        }
    }

    /**
     * 盘点米数审核接口执行，一小时一次
     */
    @Async
    @Scheduled(fixedDelay = ONE_HOUR)
    public synchronized void inventoryMeterJob(){
        businessUtilsService.inventoryMeterBusiness();
    }

    /**
     * 盘点库位审核接口执行，20分钟一次
     */
    @Async
    @Scheduled(fixedDelay = TWENTY_MINUTE)
    public void inventoryShelfJob(){
        List<InterfaceDo> lstInterfaceDo = interfaceDoService.selectList(new EntityWrapper<InterfaceDo>()
                .eq("INTERFACECODE", EbsInterfaceEnum.FEWMS008)
                //盘点审核米数接口，只对新增的离线接口进行执行，失败的不执行
                .in("ISSUCCESS","0,2")
                .eq("SPESIGN",3L)
                .orderBy("CREATETIME"));
        if (lstInterfaceDo!=null && lstInterfaceDo.size()>0) {
            CountDownLatch countDownLatch = new CountDownLatch(lstInterfaceDo.size());
            for (InterfaceDo interfaceDo : lstInterfaceDo) {
                threadConfig.asyncServiceExecutor().execute(() -> {
                    try {
                        Map<String, Object> xmlMap = JsontoMap.parseJSON2Map(JSONObject.fromObject(interfaceDo.getParamsinfo()));
                        while (ConRunningMap.containsItem(EbsInterfaceEnum.FEWMS008 + interfaceDo.getSpesign() + interfaceDo.getQacode())) {
                            try {
                                TimeUnit.MILLISECONDS.sleep(5000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        //把接口编码+集合号放到内存中
                        ConRunningMap.addItem(EbsInterfaceEnum.FEWMS008 + interfaceDo.getSpesign() + interfaceDo.getQacode());

                        String returnInfo = wmsService.FEWMS008(xmlMap, interfaceDo.getQacode(), interfaceDo.getBatchNo());
                        String returnInfoTrim = returnInfo.replace(" ", "");
                        //接口执行结果
                        boolean interfaceExecuteResult = returnInfoTrim.contains("<code>0</code>") || returnInfoTrim.contains("\"code\":0")
                                || returnInfoTrim.contains("S000A000");

                        //更新盘点登记表库位审核状态
                        inventoryRegistrationService.updateShelfState(interfaceDo.getQacode(), interfaceExecuteResult ? 1 : 0,
                                inventoryService.selectList(new EntityWrapper<Inventory>().eq("EBS_CODE", interfaceDo.getShipno())));

                        ConRunningMap.removeItem(EbsInterfaceEnum.FEWMS008 + interfaceDo.getSpesign() + interfaceDo.getQacode());

                        interfaceDo.setReturncode(returnInfo);
                        interfaceDo.setIssuccess(interfaceExecuteResult ? "1" : "2");
                        interfaceDo.setOperatetime(DateUtils.getTime());
                        interfaceDo.setExecutenum(interfaceDo.getExecutenum() + 1);
                        if (interfaceDo.getExecutenum() == 1 && "2".equals(interfaceDo.getIssuccess())) {
                            interfaceDo.setFlasecontent(returnInfo);
                        }
                        interfaceDoService.updateById(interfaceDo);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        // 这个不管是否异常都需要数量减,否则会被堵塞无法结束
                        countDownLatch.countDown();
                    }
                });
            }

            try {
                countDownLatch.await();
                logger.info("所有线程结束");
            } catch (Exception e) {
                logger.error("阻塞异常");
            }
        }
    }

    /**
     * 定时清除厂区流水号，调拨、移库单号流水
     */
    @Async
    @Scheduled(cron="0 1 0 * * ?")
    public void fixedRateJob(){
        logger.info(DateUtils.getTime()+" >>开始日常清除厂区流水号....");
        factoryAreaService.updateSerialNum();
        logger.info(DateUtils.getTime()+" >>开始日常清除调拨单、移库单流水号....");
        factoryAreaService.updateAlloMoveSerialNum();
    }

    /**
     * 定时清除盘点单号流水
     * 每月1号
     */
    @Async
    @Scheduled(cron ="0 0 0 1 * ?")
    public void inventoryClearJob(){
        logger.info(DateUtils.getTime()+" >>开始每月清除盘点单流水号....");
        factoryAreaService.updateInventoryNum();
    }

    /**
     * 定时清除接口日志表
     * 每月1号
     */
    @Async
    @Scheduled(cron ="0 0 0 1 * ?")
    public void interfaceLogClearJob(){
        logger.info(DateUtils.getTime()+" >>开始每月清除上个月的接口日志....");
        interfaceLogService.delete(new EntityWrapper<InterfaceLog>()
                .le("CREATE_TIME", DateUtils.getMonthLaterLastDay())
                .ge("CREATE_TIME", DateUtils.getMonthLaterFirstDay()));
    }

    /**
     * 定时任务获取基础数据
     */
    @Async
    @Scheduled(cron="0 54 0 * * ?")
    public void cronJob(){
        Map<String, Object> xmlMap;
        logger.info(DateUtils.getTime()+" >>拉取厂区基础数据....");
        xmlMap = new HashMap<>(1);
        xmlMap.put("line", new HashMap<String, Object>(2) {{
            put("plantno", "");
            put("plantname", "");
        }});
        wmsService.FEWMS012(xmlMap);

        logger.info(DateUtils.getTime()+" >>拉取物料基础数据....");
        xmlMap = new HashMap<>(1);
        xmlMap.put("line", new HashMap<String, Object>(2) {{
            put("materialno", "");
            put("materialname", "");
        }});
        wmsService.FEWMS001(xmlMap);

        logger.info(DateUtils.getTime()+" >>拉取仓库基础数据....");
        xmlMap = new HashMap<>(1);
        xmlMap.put("line", new HashMap<String, Object>(3) {{
            put("plantcode", "");
            put("warehouseno", "");
            put("warehousename", "");
        }});
        wmsService.FEWMS013(xmlMap);

        logger.info(DateUtils.getTime()+" >>拉取盘具基础数据....");
        xmlMap = new HashMap<>(1);
        xmlMap.put("line", new HashMap<String, Object>(8) {{
            put("code", "1");
            put("innerdiameter", "1");
            put("outerdiameter", "1");
            put("maxcarry", "1");
            put("model", "1");
            put("type", "1");
            put("onemax", "1");
            put("two", "1");
        }});
        wmsService.FEWMS019(xmlMap);

        logger.info(DateUtils.getTime()+" >>拉取库位基础数据....");
        xmlMap = new HashMap<>(1);
        xmlMap.put("line", new HashMap<String, Object>(3) {{
            put("warehouseno", "");
            put("warehousename", "");
            put("orgid","");
        }});
        wmsService.FEWMS014(xmlMap);

        logger.info(DateUtils.getTime()+" >>拉取车间数据....");
        xmlMap = new HashMap<>(1);
        xmlMap.put("line", new HashMap<String, Object>(3) {{
            put("orgid", "");
            put("workshopnumber", "");
            put("workshopname", "");
        }});
        wmsService.FEWMS026(xmlMap);
    }
}
